package com.example.springkotlindemo

import io.r2dbc.pool.ConnectionPool
import io.r2dbc.pool.ConnectionPoolConfiguration
import org.springframework.context.annotation.Configuration
import org.springframework.boot.autoconfigure.r2dbc.R2dbcProperties

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean

import org.springframework.context.annotation.Primary
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.r2dbc.ConnectionFactoryBuilder
import io.r2dbc.spi.ConnectionFactory

import org.springframework.data.r2dbc.dialect.DialectResolver
import org.springframework.transaction.ReactiveTransactionManager
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.r2dbc.connection.R2dbcTransactionManager
import org.springframework.r2dbc.core.DatabaseClient


/**
 * @author Xu Haidong
 * @date 2023/4/24 11:27
 */
@Configuration
class MyR2DBCConfig {

    @Primary
    @Bean("ersR2dbcProperties")
    @ConfigurationProperties(prefix = "spring.r2dbc")
    fun ersR2dbcProperties(): R2dbcProperties {
        return R2dbcProperties()
    }

    @Primary
    @Bean("ersConnectionFactory")
    fun getErsConnectionFactory(
        @Qualifier("ersR2dbcProperties") ersR2dbcProperties: R2dbcProperties
    ): ConnectionFactory {
        val factory: ConnectionFactory = ConnectionFactoryBuilder
            .withUrl(ersR2dbcProperties.url)
            .username(ersR2dbcProperties.username)
            .password(ersR2dbcProperties.password)
            .build()
        val configuration = ConnectionPoolConfiguration
            .builder()
            .connectionFactory(factory)
            .validationQuery("select 1")
            .build()
        return ConnectionPool(configuration)
    }

    @Primary
    @Bean(name = ["databaseClient"])
    fun r2dbcDatabaseClient(@Qualifier("ersConnectionFactory") connectionFactory: ConnectionFactory): DatabaseClient? {
        return DatabaseClient.builder().connectionFactory(connectionFactory).build()
    }

    @Primary
    @Bean("r2dbcEntityTemplate")
    fun getR2dbcEntityTemplate(
        @Qualifier("databaseClient") databaseClient: DatabaseClient,
        @Qualifier("ersConnectionFactory") ersConnectionFactory: ConnectionFactory,
    ): R2dbcEntityTemplate {
        val dialect = DialectResolver.getDialect(ersConnectionFactory)
        return R2dbcEntityTemplate(databaseClient, dialect)
    }


    @Primary
    @Bean("reactiveTransactionManager")
    fun reactiveTransactionManager(@Qualifier("ersConnectionFactory") connectionFactory: ConnectionFactory):
            ReactiveTransactionManager {
        return R2dbcTransactionManager(connectionFactory)
    }
}